home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
network
/
ka9q
/
ka9q_src.arc
/
SMTPCLI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-07-28
|
17KB
|
791 lines
/* smtpcli.c
* Client routines for Simple Mail Transfer Protocol ala RFC821
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
* Modified 14 June 1987 by P. Karn for symbolic target addresses,
* also rebuilt locking mechanism
* Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
*/
#include <stdio.h>
#if (!ATARI_ST || LATTICE) /* DG2KK */
#include <fcntl.h>
#endif
#include "global.h"
#include "netuser.h"
#include "mbuf.h"
#include "timer.h"
#include "tcp.h"
#include "smtp.h"
#include "trace.h"
#include "cmdparse.h"
extern int16 lport; /* local port placeholder */
extern int32 resolve();
static struct timer smtpcli_t;
int32 gateway;
#ifdef SMTPTRACE
int16 smtptrace = 0; /* used for trace level */
int dosmtptrace();
#endif
int16 smtpmaxcli = MAXSESSIONS; /* the max client connections allowed */
int16 smtpcli = 0; /* number of client connections
* currently open */
static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions */
int dosmtptick(),dogateway(),dosmtpmaxcli(),mlock(),dotimer();
void quit(),abort_trans(),rejextjob(),sendit(),del_session(),del_job();
void rejectjob(),execjobs(),smtp_transaction();
struct smtp_cb *newcb(),*lookup();
struct smtp_job *setupjob();
struct cmds smtpcmds[] = {
"gateway", dogateway, 0, NULLCHAR, NULLCHAR,
"kick", dosmtptick, 0, NULLCHAR, NULLCHAR,
"maxclients", dosmtpmaxcli, 0, NULLCHAR, NULLCHAR,
"timer", dotimer, 0, NULLCHAR, NULLCHAR,
#ifdef SMTPTRACE
"trace", dosmtptrace, 0, NULLCHAR, NULLCHAR,
#endif
NULLCHAR, NULLFP, 0,
"subcommands: gateway kick maxclients timer trace",
NULLCHAR,
};
dosmtp(argc,argv)
int argc;
char *argv[];
{
return subcmd(smtpcmds,argc,argv);
}
static int
dosmtpmaxcli(argc,argv)
int argc;
char *argv[];
{
int x;
if (argc < 2)
printf("%d\n",smtpmaxcli);
else {
x = atoi(argv[1]);
if (x > MAXSESSIONS)
printf("max clients must be <= %d\n",MAXSESSIONS);
else
smtpmaxcli = x;
}
return 0;
}
static int
dogateway(argc,argv)
int argc;
char *argv[];
{
char *inet_ntoa();
int32 n;
extern char badhost[];
if(argc < 2){
printf("%s\n",inet_ntoa(gateway));
} else if((n = resolve(argv[1])) == 0){
printf(badhost,argv[1]);
return 1;
} else
gateway = n;
return 0;
}
#ifdef SMTPTRACE
static int
dosmtptrace(argc,argv)
int argc;
char *argv[];
{
if (argc < 2)
printf("%d\n",smtptrace);
else
smtptrace = atoi(argv[1]);
return 0;
}
#endif
/* Set outbound spool poll interval */
static int
dotimer(argc,argv)
int argc;
char *argv[];
{
int dosmtptick();
if(argc < 2){
printf("%d/%d\n",smtpcli_t.start - smtpcli_t.count,
smtpcli_t.start);
return 0;
}
smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
smtpcli_t.arg = NULLCHAR; /* dummy value */
smtpcli_t.start = atoi(argv[1]); /* set timer duration */
start_timer(&smtpcli_t); /* and fire it up */
return 0;
}
/* this is the routine that gets called every so often to do outgoing mail
processing */
int
dosmtptick()
{
register struct smtp_cb *cb;
char tmpstring[LINELEN], wfilename[13], prefix[9];
char from[LINELEN], to[LINELEN];
char *cp, *cp1;
int32 destaddr;
FILE *wfile;
#ifdef SMTPTRACE
if (smtptrace > 5) {
printf("smtp daemon entered\n");
fflush(stdout);
}
#endif
for(filedir(mailqueue,0,wfilename);wfilename[0] != '\0';
filedir(mailqueue,1,wfilename)){
/* save the prefix of the file name which it job id */
cp = wfilename;
cp1 = prefix;
while (*cp && *cp != '.')
*cp1++ = *cp++;
*cp1 = '\0';
/* lock this file from the smtp daemon */
if (mlock(mailqdir,prefix))
continue;
sprintf(tmpstring,"%s%s",mailqdir,wfilename);
if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
/* probably too many open files */
(void) rmlock(mailqdir,prefix);
/* continue to next message. The failure
* may be temporary */
continue;
}
fgets(tmpstring,LINELEN,wfile); /* read target host */
rip(tmpstring);
fgets(from,LINELEN,wfile); /* read target host */
rip(from);
fgets(to,LINELEN,wfile); /* read target user */
rip(to);
fclose(wfile);
if ((destaddr = mailroute(tmpstring)) == 0) {
printf("** smtpcli: Unknown address %s\n",tmpstring);
fflush(stdout);
(void) rmlock(mailqdir,prefix);
continue;
}
if ((cb = lookup(destaddr)) == NULLCB) {
/* there are enough processes running already */
if (smtpcli >= smtpmaxcli) {
#ifdef SMTPTRACE
if (smtptrace) {
printf("smtp daemon: too many processes\n");
fflush(stdout);
}
#endif
(void) rmlock(mailqdir,prefix);
break;
}
if ((cb = newcb()) == NULLCB) {
(void) rmlock(mailqdir,prefix);
break;
}
cb->ipaddr = destaddr;
} else {
/* This system is already is sending mail lets not
* interfere with its send queue.
*/
if (cb->state != CLI_IDLE) {
(void) rmlock(mailqdir,prefix);
continue;
}
}
#ifdef SMTPTRACE
if (smtptrace > 1) {
printf("queue job %s To: %s From: %s\n",prefix,to,from);
fflush(stdout);
}
#endif
if (setupjob(cb,prefix,to,from) == NULLJOB) {
(void) rmlock(mailqdir,prefix);
del_session(cb);
break;
}
}
/* start sending that mail */
execjobs();
/* Restart timer */
start_timer(&smtpcli_t);
#ifdef SMTPTRACE
if (smtptrace > 5) {
printf("smtp daemon done\n");
fflush(stdout);
}
#endif
}
/* this is the master state machine that handles a single SMTP transaction */
void
smtp_transaction(cb)
struct smtp_cb *cb;
{
void smtp_cts();
char reply;
int rcode;
#ifdef SMTPTRACE
if (smtptrace > 7)
printf("smtp_transaction() enter state=%u\n",cb->state);
if (smtptrace) {
printf("%s\n",cb->buf);
fflush(stdout);
}
#endif
/* Another line follows; ignore this one */
if(cb->buf[0] == '0' || cb->buf[3] == '-')
return;
reply = cb->buf[0];
rcode = atoi(cb->buf);
/* if service shuting down */
if (rcode == 421) {
quit(cb);
return;
}
switch(cb->state) {
case CLI_OPEN_STATE:
if (reply != '2')
quit(cb);
else {
cb->state = CLI_HELO_STATE;
sendit(cb,"HELO %s\r\n",hostname);
}
break;
case CLI_HELO_STATE:
if (reply != '2')
quit(cb);
else {
cb->state = CLI_MAIL_STATE;
/* send both to speed things up */
sendit(cb,"MAIL FROM:<%s>\r\nRCPT TO:<%s>\r\n",
cb->jobq->from,cb->jobq->to);
}
break;
case CLI_MAIL_STATE:
if (reply != '2')
quit(cb);
else {
cb->state = CLI_RCPT_STATE;
/* the RCPT is sent already */
}
break;
case CLI_RCPT_STATE:
if (reply == '5') {
rejectjob(cb);
abort_trans(cb);
} else if (reply != '2')
abort_trans(cb);
else {
/* open text file here because it will be too
* late to abort in the data state.
*/
/* if this file open fails abort */
if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
abort_trans(cb);
else {
cb->state = CLI_DATA_STATE;
sendit(cb,"DATA\r\n");
}
}
break;
case CLI_DATA_STATE:
if (reply != '3')
abort_trans(cb);
else {
cb->state = CLI_SEND_STATE;
/* Kick the data transfer to get it started */
smtp_cts(cb->tcb,cb->tcb->window - cb->tcb->sndcnt);
}
break;
case CLI_SEND_STATE:
/* the transmitter upcall routine will advance the
state pointer on end of file, so we do nada... */
break;
case CLI_UNLK_STATE:
if (reply == '5') {
rejectjob(cb);
abort_trans(cb);
} else if (reply != '2')
abort_trans(cb);
else {
unlink(cb->wname); /* unlink workfile */
/* close and unlink the textfile */
if(cb->tfile != NULLFILE) {
fclose(cb->tfile);
cb->tfile = NULLFILE;
}
unlink(cb->tname);
abort_trans(cb);
}
break;
case CLI_QUIT_STATE:
close_tcp(cb->tcb); /* close up connection */
break;
}
}
/* abort the currrent job. Remove the lockfile.
* If more work exists set up the next job if
* not then shut down.
*/
static void
abort_trans(cb)
struct smtp_cb *cb;
{
if(cb->tfile != NULLFILE) {
fclose(cb->tfile);
cb->tfile = NULLFILE;
}
(void) rmlock(mailqdir,cb->jobq->jobname);
if (nextjob(cb)) {
sendit(cb,"RSET\r\n");
cb->state = CLI_HELO_STATE;
} else {
sendit(cb,"